import httplib
import urllib
import re
import sys
import time
import debug

from custom_exceptions import *

import global_vars as gv

USER_AGENT = "google-voice-for-s60/1.1"
LOGIN_URL = 'https://www.google.com/accounts/ClientLogin'
INBOX_URL = 'https://www.google.com/voice/'
CALL_URL = 'https://www.google.com/voice/call/connect/'
SEND_SMS_URL = 'https://www.google.com/voice/sms/send/'
LOGOUT_URL = 'https://www.google.com/voice/account/signout'
HANGUP_URL ='https://www.google.com/voice/call/cancel/'
MAX_REDIRECT_COUNT = 5

class SimpleCookieJar(object):
    cookie_re = re.compile(r"(?i)set-cookie: (\w+)=([^;]+).*")
    def __init__(self):
        self.cookies = {}
    def addCookies(self, response):
        for header in response.msg.headers:

            m = self.cookie_re.match(header)
            if not m:
                continue
            if gv.DO_DEBUG:
                debug.log(header)
                debug.log(m.group(2))
            self.cookies[m.group(1)] = m.group(2)
    def addCookie(self, key, value):
        self.cookies[key] = value
    def get(self):
        return "; ".join("%s=%s" % kv for kv in self.cookies.iteritems())

class GoogleVoiceInterop(object):


    def __init__(self, username, password):
        self.username = username
        self.password = password
        self.cj = SimpleCookieJar()
        self.h = httplib.HTTPSConnection("www.google.com")

        self.auth = None
        self.magic_rnr_se = None

    def login(self):
        if gv.DO_DEBUG: debug.log('google_voice_interop.login')
        #first go to the auth page and retrieve the login token
        redirect_count = 0
        url = LOGIN_URL
        while url:
            if redirect_count == MAX_REDIRECT_COUNT: raise MaxRedirectReached("Maximum redirect countreached. ")

            response, html = self.doRequest(
                method="GET", url=url + "?" + urllib.urlencode({"Email":self.username,"Passwd":self.password, "source":USER_AGENT,"service":"grandcentral","accountType":"GOOGLE"}) ,
                headers={})
            url = response.getheader("location")
            redirect_count += 1
            if gv.DO_DEBUG and url: debug.log("redirecting to:%s" % url)

        error = re.search(r'Error=([A-z]+)', html)
        if error:
            if gv.DO_DEBUG: debug.log('google_voice_interop.login login error')
            raise UnableToLogin(error.group(1))

        self.auth = re.search(r'Auth=([A-z0-9_-]+)', html)

        if not self.auth:
            if gv.DO_DEBUG: debug.log('google_voice_interop.login cant find auth token')
            raise CantFindAuthToken("Can't find Auth token.")

        self.auth = self.auth.group(1)
        if gv.DO_DEBUG: debug.log("Auth=%s" % self.auth)

        #go to inbox and get magic_rnr_se
        redirect_count = 0
        url = INBOX_URL
        while url:
            if redirect_count == MAX_REDIRECT_COUNT: raise MaxRedirectReached("Maximum redirect countreached. ")

            response, html = self.doRequest(
                method="GET", url=url ,
                headers = {"Authorization":'GoogleLogin auth=' + self.auth})

            redirect_count += 1
            url = response.getheader("location")

            if gv.DO_DEBUG and url: debug.log("redirecting to:%s" % url)

        self.magic_rnr_se = re.search(r"'_rnr_se'\: '([^']+)'", html)

        if not self.magic_rnr_se:
            if gv.DO_DEBUG: debug.log('google_voice_interop.login cant find rnr number')
            raise CantFindMagicRNRToken("Can't find _rnr_se.  Not logged in?")

        self.magic_rnr_se = self.magic_rnr_se.group(1)

        if gv.DO_DEBUG: debug.log('google_voice_interop.login Finished.')

    def place_call(self, via, number):
        if gv.DO_DEBUG: debug.log("google_voice_interop.place_call  to: %s via: %s" % (number, via))

        if not self.auth:
            self.login()

        postdata = urllib.urlencode({ "outgoingNumber": number,
                                      "forwardingNumber": via,
                                      "_rnr_se": self.magic_rnr_se,
                                      "subscriberNumber":"undefined",
                                      "phoneType":"2",
                                      "remember":"0" })

        if gv.DO_DEBUG:
            debug.log(postdata)

        response, http = self.doRequest(
            method="POST", url=CALL_URL,
            body=postdata,
            headers={ "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
                      'Referer':'https://www.google.com/voice/',
                      'Content-Length':len(postdata),
                      'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                      "Authorization":'GoogleLogin auth=' + self.auth })

        if not self._eval_call_response(http):
            if gv.DO_DEBUG: debug.log("google_voice_interop.place_call http: %s" % http)
            raise UnableToPlaceCall("Google API declined to place the call")

        if gv.DO_DEBUG: debug.log("google_voice_interop.place_call Finished")

    def _eval_call_response(self,s):
        try:
            true = True
            false = False
            ret = eval(s)
            return ret["ok"]
        except:
            return False

    def cancel_call(self):
        if gv.DO_DEBUG: debug.log("google_voice_interop.cancel_call")

        if not self.auth:
            self.login()

        postdata = urllib.urlencode({ "outgoingNumber": "undefined",
                                      "forwardingNumber": "undefined",
                                      "_rnr_se": self.magic_rnr_se,
                                      "cancelType":"C2C" })

        response, http = self.doRequest(
            method="POST", url=HANGUP_URL + '?' + urllib.urlencode({"auth":self.auth}),
            body=postdata,
            headers={ "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
                      'Referer':'https://www.google.com/voice/',
                      'Content-Length':len(postdata),
                      'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                      "Authorization":'GoogleLogin auth=' + self.auth })

    def send_sms(self,number,text):
        if not self.auth:
            self.login()

        postdata = urllib.urlencode({ "phoneNumber":number,
                                      "text": text,
                                      "_rnr_se": self.magic_rnr_se })
        response, http = self.doRequest(
            method="POST", url=SEND_SMS_URL,
            body=postdata,
            headers={ "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
                      'Referer':'https://www.google.com/voice/',
                      'Content-Length':len(postdata),
                      'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                      "Authorization":'GoogleLogin auth=' + self.auth })

        if not self._eval_call_response(http):
            if gv.DO_DEBUG: debug.log("google_voice_interop.send_sms http: %s" % http)
            raise UnableToSendSMS("Google API declined to send teh SMS")

    def logout(self):
        if gv.DO_DEBUG: debug.log('google_voice_interop.logout')
        self.doRequest(
            method="GET", url=LOGOUT_URL + '?' + urllib.urlencode({"auth":self.auth}),
            headers={ "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
                      'Referer':'https://www.google.com/voice/'})


    def doRequest(self, headers, **kw):
        headers["User-agent"] = USER_AGENT
        headers["Cookie"] = self.cj.get()
        if gv.DO_DEBUG: debug.log("ReadCookie:%s" % self.cj.get())
        self.h.request(headers=headers, **kw)
        response = self.h.getresponse()
        self.cj.addCookies(response)
        return response, response.read()


def main():
    gv.DO_DEBUG = True
    httplib.HTTPConnection.debuglevel = 1
    gvi = GoogleVoiceInterop('raf1hh','bl00dl1ne')
    gvi.place_call('9499035059','9493026004')
    #gvi.send_sms('xxx', 'xxx')
    #gvi.cancel_call()
    #gvi.logout()

if __name__ == '__main__':
    main()